<?php


namespace App\Task;


use App\Game\Conf\MainCmd;
use App\Game\Conf\SubCmd;
use App\Game\Core\Packet;

class CatchCardTask
{

    /**
     * 用户摸牌逻辑处理
     * @param $user_room_data
     * @param $out_cards
     * @param $account
     * @param $fd
     * @throws \Exception
     */
    public function doCatch($user_room_data, $out_cards, $account, $fd): void
    {
        $game_conf = config('game');
        $user_conf = config('user');
        $serv = server();
        $room_no = json_decode($user_room_data['room_no'], true);

        //游戏进度：0.加入游戏阶段 1.准备阶段 2.换牌阶段 3.定缺阶段 4.出牌阶段 5.摸牌阶段 6.结算阶段
        $room_progress_key = sprintf($game_conf['user_room_progress'], $room_no);
        if (redis()->exists($room_progress_key)) {
            $progress = redis()->get($room_progress_key);
            if ($progress != 5) {
                $msg = array('status' => 1, 'info' => '摸牌非法, 还未到摸牌阶段！');
                $this->gameCatchCard($serv, $fd, $msg);
                return;
            }
        }
        $flag = true;

        //检查轮次
        $next_chair_id = json_decode($user_room_data['next_chair_id'], true);
        if ($next_chair_id != $this->findChairId($room_no, $account)) {
            $msg = array('status' => 1, 'info' => '摸牌非法, 还未轮到您摸牌！');
            $flag = $this->gameCatchCard($serv, $fd, $msg);
            return;
        }
//        dd('user_room_data[hand]', $user_room_data['hand']);
        $hand = json_decode($user_room_data['hand'], true);
        if (gettype($hand) == 'string') {
            $hand = json_decode($hand, true);
        }
//        dd('hand', $hand);
        //判断底牌剩余数，没有则游戏结束
        if (count($hand) < 1) {
            $msg = array('status' => 2, 'info' => '摸牌非法，游戏已结束');
            $flag = $this->gameCatchCard($serv, $fd, $msg);
        }
        //底牌拿出一张牌
        $arr = array_splice($hand, 0, 1);
        $moCard = $arr[0];
        $my_card = json_decode($user_room_data[$account], true);
        $my_card['card'][] = $moCard;
        //判断总手牌数，是否存在重复摸牌
        $totalCardNum = count($my_card['card']);
        $gangNum = isset($my_card['gang']) ? count($my_card['gang']) : 0;
        if ($gangNum == 0 && $totalCardNum != 14) {
            $msg = array('status' => 3, 'info' => '摸牌非法，重复摸牌');
            $flag = $this->gameCatchCard($serv, $fd, $msg);
        }
        if ($gangNum == 1 && $totalCardNum != 15) {
            $msg = array('status' => 3, 'info' => '摸牌非法，重复摸牌');
            $flag = $this->gameCatchCard($serv, $fd, $msg);
        }
        if ($gangNum == 2 && $totalCardNum != 16) {
            $msg = array('status' => 3, 'info' => '摸牌非法，重复摸牌');
            $flag = $this->gameCatchCard($serv, $fd, $msg);
        }
        if ($gangNum == 3 && $totalCardNum != 17) {
            $msg = array('status' => 3, 'info' => '摸牌非法，重复摸牌');
            $flag = $this->gameCatchCard($serv, $fd, $msg);
        }
        if ($gangNum == 4 && $totalCardNum != 18) {
            $msg = array('status' => 3, 'info' => '摸牌非法，重复摸牌');
            $flag = $this->gameCatchCard($serv, $fd, $msg);
        }
        if ($flag) {
            $my_card = $this->setMyCard($user_room_data, $moCard, $hand, $account);
            redis()->set($room_progress_key, 4);
            //给自己发送通知，包含所摸牌的信息
            $user_room_info = Packet::packFormat('OK', 1, ['card' => $moCard, 'chair_id'
            => $out_cards['chair_id']]);
            $return_data = Packet::packEncode($user_room_info, MainCmd::CMD_SYS, SubCmd::SUB_GAME_CATCH_CARD_RESP);
            $serv->push($fd, $return_data, WEBSOCKET_OPCODE_BINARY);
            //给其他人发送通知，不含所摸牌的信息
            $uinfo = json_decode($user_room_data['uinfo'], true);
            $fds = $this->getUsers($uinfo, $game_conf);// 房间玩家链接
            $user_room_info = Packet::packFormat('OK', 1, ['chair_id'
            => $out_cards['chair_id'], 'hand_num' => count($hand)]);
            $return_data = Packet::packEncode($user_room_info, MainCmd::CMD_SYS, SubCmd::SUB_GAME_CATCH_CARD_RESP);
            foreach ($fds as $fdv) {
                //获取客户端信息
                $client_info = $serv->getClientInfo($fdv);
                $client[$fdv] = $client_info;
                if (isset($client_info['websocket_status']) && $client_info['websocket_status'] == 3) {
                    $serv->push($fdv, $return_data, WEBSOCKET_OPCODE_BINARY);
                }
            }
        }

    }

    /**
     * 返回玩家房间桌位号
     * @param $room_no
     * @param $account
     * @return mixed
     */
    protected function findChairId($room_no, $account)
    {
        $game_conf = config('game');
        $room_chair_key = sprintf($game_conf['user_room_chair'], $room_no);
        $chair_data = json_decode(redis()->get($room_chair_key), true);
        return $chair_data[$account];
    }

    /**
     * 向客户端当前玩家发送错误提示响应, 单发
     * @param $serv
     * @param $fd
     * @param $param
     * @return bool
     */
    protected function gameCatchCard($serv, $fd, $param)
    {
        $data = Packet::packFormat('OK', 0, $param);
        $data = Packet::packEncode($data, MainCmd::CMD_SYS, SubCmd::SUB_GAME_CATCH_CARD_RESP);
        $serv->push($fd, $data, WEBSOCKET_OPCODE_BINARY);
        return false;
    }


    /**
     * 设置我的手牌
     * @param $user_room_data
     * @param $cards
     * @param $account
     * @return mixed
     */
    protected function setMyCard($user_room_data, $card, $hand, $account)
    {
        //根据椅子查询手牌信息
        $my_card = json_decode($user_room_data[$account], true);
        $my_card['card'][] = $card;
        sort($my_card['card']);
        $param[$account] = json_encode($my_card);
        $param['hand'] = json_encode($hand);
        if (count($hand) == 0) {
            $param['is_game_over'] = 1;
        }
        //写会redis
        $this->updateRoomData($user_room_data['room_no'], $param);
        return $my_card;
    }


    /**
     * 批量更新房间数据
     * @param $room_no
     * @param $params
     */
    protected function updateRoomData($room_no, $params)
    {
        if (gettype($room_no)) {
            $room_no = json_decode($room_no, true);
        }
        $game_conf = config('game');
        $room_data_key = sprintf($game_conf['user_room_data'], $room_no);
        dd('room_data_key', $room_data_key);
        ddNode(1);
        if (redis()->exists($room_data_key)) {
            ddNode(2);
            foreach ($params as $key => $val) {
                ddNode(3);
                dd('key', $key);
                dd('val', $val);
                redis()->hSet($room_data_key, (string)$key, $val);
            }
        }
    }


    /**
     * 房间广播
     * @param $serv
     * @param $fds
     * @param $data
     */
    protected function roomBroadcast($serv, $fds, $data)
    {
        $user_room_info = Packet::packFormat('OK', 1, $data);
        $return_data = Packet::packEncode($user_room_info, MainCmd::CMD_SYS, SubCmd::SUB_GAME_CATCH_CARD_RESP);
        foreach ($fds as $fd) {
            //获取客户端信息
            $client_info = $serv->getClientInfo($fd);
            $client[$fd] = $client_info;
            if (isset($client_info['websocket_status']) && $client_info['websocket_status'] == 3) {
                $serv->push($fd, $return_data, WEBSOCKET_OPCODE_BINARY);
            }
        }
    }

    /**
     * 取出房间所有用户
     * @param $user_info
     * @param $game_conf
     * @return array
     */
    protected function getUsers($user_info, $game_conf)
    {
        $users = [];
        $uinfo = json_decode($user_info, true);
        foreach ($uinfo as $k => $v) {
            $user_bind_key = sprintf($game_conf['user_bind_key'], $k);
            $users[] = redis()->get($user_bind_key);
        }
        return $users;
    }

}